﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Common.Entitys.CommonLogs;
using Common.Entitys.Messages;
using Common.Utlis;
using Common.Utlis.Extend;
using Org.BouncyCastle.Utilities.Encoders;

namespace Common.Utils
{
    public class TcpClientHelp<TSend> where TSend : BaseBytesMsg
    {
        public TcpClientHelp()
        {
            if (typeof(TSend) != typeof(BaseBytesMsg))
            {
                MessageAggregator<TSend>.Subscribe(OnTSend);
            }
        }

        /// <summary>
        /// 工作进程IP
        /// </summary>
        private string m_WorkAppIP = "127.0.0.1";


        /// <summary>
        /// 工作进程Server
        /// </summary>
        private int m_WorkAppPort = 8086;

        private volatile bool m_IsTaskRun = true;


        private Socket m_ClientSocket;

        /// <summary>
        /// 初始化
        /// </summary>
        public void Init(string ip, int port)
        {
            m_WorkAppIP = ip;
            m_WorkAppPort = port;
            Task task = new Task(Connect, TaskCreationOptions.LongRunning);
            task.Start();
        }

        public void SendBytes(Byte[] bytes, int times = 0)
        {
            try
            {
                if (times > 10)
                {
                    LogHelp.AddLog<WarnLogEntity>($"向 服务器IP：{m_WorkAppPort}  端口号：{m_WorkAppPort} 连续发送10次失败 原因未知 ");
                }
                int length = bytes.Length;
                DateTime dtStartTime = DateTime.Now;
                int sendLength = m_ClientSocket.Send(bytes);
                TimeSpan ts = DateTime.Now - dtStartTime;
                if (length != sendLength)
                {
                    byte[] lastBytes = bytes.Copy(sendLength, length - sendLength);
                    //发送剩余的Byte
                    SendBytes(lastBytes, times++);
                }
            }
            catch (Exception e)
            {
                Thread.Sleep(50);
                SendBytes(bytes, ++times);
            }
        }


        private void OnTSend(TSend tSend)
        {
            SendBytes(tSend.Bytes);
        }

        /// <summary>
        /// 连接
        /// 一共两个逻辑
        /// 1 没有连上一直连 2已经连上断线重连
        /// </summary>
        private void Connect()
        {
            try
            {
                IPAddress ipAddress = IPAddress.Parse(m_WorkAppIP);
                IPEndPoint ipEndPoint = new IPEndPoint(ipAddress, m_WorkAppPort);
                m_ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                byte[] date = new byte[1000000];
                //等待主线程启动逻辑
                while (true)
                {
                    try
                    {
                        m_ClientSocket.Connect(ipEndPoint);
                        break;
                    }
                    catch (Exception ex)
                    {
                        Thread.Sleep(100);
                    }
                }

                //断线重连逻辑
                while (m_IsTaskRun)
                {
                    try
                    {
                        //断线重连逻辑
                        if (!m_ClientSocket.Connected)
                        {
                            // LogHelp.AddLog<LogEncity>("激光雷达已经断开连接,正在重新连接");
                            try
                            {
                                m_ClientSocket.Dispose();
                                m_ClientSocket = null;
                                m_ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                                m_ClientSocket.Connect(ipEndPoint);
                            }
                            catch (Exception e)
                            {
                                // LogHelp.AddLog<LogEncity>("激光雷达重新连接失败");
                            }
                        }
                        Thread.Sleep(100);

                    }
                    catch (Exception e)
                    {
                        // LogHelp.AddLog("接收激光雷达数据异常", e);
                    }
                }
            }
            catch (Exception e)
            {
                // LogHelp.AddLog("TCP连接激光雷达失败", e);
            }
        }



    }

    public class TcpClientHelp
    {
        /// <summary>
        /// 工作进程IP
        /// </summary>
        private string m_WorkAppIP; // 127.0.0.1


        /// <summary>
        /// 工作进程Server
        /// </summary>
        private int m_WorkAppPort; // 8086

        private volatile bool m_IsTaskRun = true;

        /// <summary>
        /// 是否被连过 连过一次就算 用于区别设备设备不存在和设备断线重连
        /// </summary>
        private volatile bool m_IsAccept = false;

        public Socket m_ClientSocket;

        /// <summary>
        /// 初始化
        /// </summary>
        public void Init(string ip, int port)
        {
            m_WorkAppIP = ip;
            m_WorkAppPort = port;
            Task task = new Task(Connect, TaskCreationOptions.LongRunning);
            task.Start();
        }

        public void SendBytes(Byte[] bytes, int times = 0,int maxTimes=10)
        {
            try
            {
                if (!m_IsAccept)
                {
                   return; 
                }

                if (times > 10)
                {
                    LogHelp.AddLog<WarnLogEntity>($"向 服务器IP：{m_WorkAppIP}  端口号：{m_WorkAppPort} 连续发送10次失败 原因未知 {Hex.ToHexString(bytes)}");
                    return;
                }
                if (!m_ClientSocket.Connected)
                {
                    //重连一下 并记录日志
                    LogHelp.AddLog<WarnLogEntity>($"Clinet 和服务器IP：{m_WorkAppIP}  端口号：{m_WorkAppPort} 断开连接 ");
                    Thread.Sleep(50);
                    SendBytes(bytes, ++times);
                    return;
                }
                int length = bytes.Length;
                int sendLength = m_ClientSocket.Send(bytes);
                if (length != sendLength)
                {
                    byte[] lastBytes = bytes.Copy(sendLength, length - sendLength);
                    //发送剩余的Byte
                    SendBytes(lastBytes,times);
                }
            }
            catch (Exception e)
            {
                Thread.Sleep(50);
                SendBytes(bytes, ++times);
            }
        }

        /// <summary>
        /// 接收
        /// </summary>
        public Action<byte[]> ReceiveAction;

        /// <summary>
        /// 发送
        /// </summary>
        /// <param name="bytes"></param>
        public void OnTSend(Byte[] bytes)
        {
            SendBytes(bytes);
        }
        /// <summary>
        /// 轻刮 【断开连接时，只发送一次消息】
        /// </summary>
        private bool IsSendMessage = true;

        /// <summary>
        /// 连接
        /// 一共两个逻辑
        /// 1 没有连上一直连 2已经连上断线重连
        /// </summary>
        private void Connect()
        {
            try
            {
                IPAddress ipAddress = IPAddress.Parse(m_WorkAppIP);
                IPEndPoint ipEndPoint = new IPEndPoint(ipAddress, m_WorkAppPort);


                m_ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                DisposeMsg dispose = new DisposeMsg(m_ClientSocket);
                MessageAggregator<DisposeMsg>.Publish(dispose);
                byte[] data = new byte[1000000];
                //等待主线程启动逻辑
                while (true)
                {
                    try
                    {
                        // todo 这里使用捕获异常的方式比较消耗性能可以先Ping通后连接
                        m_ClientSocket.Connect(ipEndPoint);
                        m_IsAccept = true;
                        TcpConnectMsg tcpConnectMsg = new TcpConnectMsg(m_WorkAppIP, m_WorkAppPort);
                        MessageAggregator<TcpConnectMsg>.Publish(tcpConnectMsg);
                        MessageAggregator<StringInfoMsg>.Publish(new StringInfoMsg() { Title = "TCP_Client",PropertyName = "UpperComputerConnectAlarm", Content = "" }, "平板报警消息");
                        break;
                    }
                    catch (Exception ex)
                    {
                        Thread.Sleep(100);
                    }
                }

                //断线重连逻辑
                while (m_IsTaskRun)
                {
                    try
                    {
                        //断线重连逻辑
                        if (!m_ClientSocket.Connected)
                        {
                            LogHelp.AddLog<WarnLogEntity>($"Tcp客户端 {m_WorkAppIP}:{m_WorkAppPort}  已经断开连接,正在重新连接");
                            if (IsSendMessage)
                            {
                                MessageAggregator<StringInfoMsg>.Publish(new StringInfoMsg() { Title = "TCP_Client", PropertyName = "UpperComputerConnectAlarm", Content = "连接上位机异常" }, "平板报警消息");
                                IsSendMessage = false;
                            }

                           
                            try
                            {
                                m_ClientSocket.Dispose();
                                m_ClientSocket = null;
                                m_ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                                m_ClientSocket.Connect(ipEndPoint);
                                //如果连接上会执行这个，否则直接抛异常
                                IsSendMessage = true;
                                MessageAggregator<StringInfoMsg>.Publish(new StringInfoMsg() { Title = "TCP_Client", PropertyName = "UpperComputerConnectAlarm", Content = "" }, "平板报警消息");
                            }
                            catch (Exception e)
                            {
                                LogHelp.AddLog<WarnLogEntity>($"Tcp客户端 {m_WorkAppIP}:{m_WorkAppPort}重新连接失败");
                            }
                            Thread.Sleep(100);
                        }
                        else
                        {
                           
                            int length = m_ClientSocket.Receive(data);
                            if (length == 0)
                            {
                                continue;
                            }

                            if (ReceiveAction == null)
                            {
                                continue;
                            }
                            Byte[] bytes = data.Copy(length);
                            ReceiveAction.Invoke(bytes);
                        }


                    }
                    catch (Exception e)
                    {
                        // LogHelp.AddLog("接收激光雷达数据异常", e);
                    }
                }
            }
            catch (Exception e)
            {
                // LogHelp.AddLog("TCP连接激光雷达失败", e);
            }
        }
    }
}
